---
title: User Onboarding
description: Implementing a user onboarding page and collecting information on sign-up
---

By default, Stack Auth collects information such as email addresses from OAuth providers. Sometimes, you may want to collect additional information from users during sign-up, for example a name or address.

The most straightforward approach is to redirect users to an onboarding page right after they sign up. However, this is not recommended for the following reasons:

1. Users can accidentally (or purposefully) close or navigate away from the page before completing the onboarding.
2. Redirect URLs may vary depending on the context. For instance, if a user is redirected to a sign-in page after trying to access a protected page, they'll expect to return to the original protected page post-authentication.

Instead, a more reliable strategy is to store an `onboarded` flag in the user's metadata and redirect users to the onboarding page if they haven't completed it yet.

## Example implementation

Let's say you have an onboarding page that asks for an address and stores it in the user's [metadata](../concepts/custom-user-data.mdx):

```jsx title="app/onboarding/page.tsx"
export default function OnboardingPage() {
  const user = useUser();
  const router = useRouter();
  const [address, setAddress] = useState('');


  return <>
    <input 
      type="text" 
      value={address} 
      onChange={(e) => setAddress(e.target.value)} 
    />

    <button onClick={async () => {
      await user.update({
        clientMetadata: {
          onboarded: true,
          address,
        },
      });
      router.push('/');
    }}>
      Submit
    </button>
    </>
  );
}
```

<Info>
While the above implementation offers a basic onboarding process, users can still skip onboarding by directly sending an API request to update the `clientMetadata.onboarded` flag. If you want to ensure that onboarding cannot be bypassed on the API level, you should create a server endpoint to validate and store the data, then save the `onboarded` flag in the `clientReadOnlyMetadata` on the server side after validation.
</Info>

Next, we can create a hook/function to check if the user has completed onboarding and redirect them to the onboarding page:

<Tabs defaultValue="client">
  <TabsList>
    <TabsTrigger value="client">Client Hook</TabsTrigger>
    <TabsTrigger value="server">Server Function</TabsTrigger>
  </TabsList>
  <TabsContent value="client">
    ```jsx title="app/onboarding-hooks.ts"
    'use client';
    import { useEffect } from 'react';
    import { useUser } from '@stackframe/stack';
    import { useRouter } from 'next/navigation';

    export function useOnboarding() {
      const user = useUser();
      const router = useRouter();

      useEffect(() => {
        if (!user.clientReadOnlyMetadata.onboarded) {
          router.push('/onboarding');
        }
      }, [user]);
    }
    ```
  </TabsContent>
  <TabsContent value="server">
    ```jsx title="app/onboarding-functions.ts"
    import { stackServerApp } from '@/stack/server';
    import { redirect } from 'next/navigation';

    export async function ensureOnboarded() {
      const user = await stackServerApp.getUser();
      if (!user.clientReadOnlyMetadata.onboarded) {
        redirect('/onboarding');
      }
    }
    ```
  </TabsContent>
</Tabs>

You can then use these functions wherever onboarding is required:

<Tabs defaultValue="client">
  <TabsList>
    <TabsTrigger value="client">Client Component</TabsTrigger>
    <TabsTrigger value="server">Server Component</TabsTrigger>
  </TabsList>
  <TabsContent value="client">
    ```jsx title="app/page.tsx"
    import { useOnboarding } from '@/app/onboarding-hooks';
    import { useUser } from '@stackframe/stack';

    export default function HomePage() {
      useOnboarding();
      const user = useUser();

      return (
        <div>Welcome to the app, {user.displayName}</div>
      );
    }
    ```
  </TabsContent>
  <TabsContent value="server">
    ```jsx title="app/page.tsx"
    import { ensureOnboarding } from '@/app/onboarding-functions';
    import { stackServerApp } from '@/stack/server';

    export default async function HomePage() {
      await ensureOnboarding();
      const user = await stackServerApp.getUser();

      return (
        <div>Welcome to the app, {user.displayName}</div>
      );
    }
    ```
  </TabsContent>
</Tabs>
